package org.scut.gis.spider.processor;

import org.apache.commons.collections4.MapUtils;
import org.scut.gis.spider.data.entity.Response;
import org.scut.gis.spider.data.entity.Task;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.LinkedList;

/**
 * 网络访问
 * @author dandan
 */
@Component
public class Fetcher {

    /**
     * 存储异步访问返回结果
     */
    private static LinkedList<Response> ResponseLits;
    private static WebClient webClient;

    public void init() {
        webClient = WebClient.create();
    }

    public void run() {
        // 获取任务
        // Response response = fetch(task);
        // 写入队列
    }

    public Response fetch(Task task) {
        final Response response = new Response();
        try {
            // 转换
            URI uri = new URI(task.getUrl());
            HttpMethod httpMethod = httpMethodResolver(task);
            HttpHeaders httpHeaders = httpHeadersResolver(task);
            MultiValueMap<String, String> cookies = cookiesResolver(task);

            // 流式调用请求
            Mono<String> contentMono = webClient
                    .method(httpMethod)
                    .uri(uri)
                    .headers(x->{
                        httpHeaders.forEach((header, value)-> {
                            x.remove(header);
                            x.addAll(header, value);
                        });
                    }).cookies( x -> {
                        cookies.forEach((cookie, value)->{
                            x.remove(cookie);
                            x.addAll(cookie, value);
                        });
                    }).exchange()
                    .flatMap(clientResponse -> {
                        // 设置返回值
                        HttpStatus httpStatus = clientResponse.statusCode();
                        response.setStatusCode(httpStatus.value());
                        response.setStatus(httpStatus.getReasonPhrase());

                        clientResponse.headers();
                        clientResponse.cookies();

                        return clientResponse.bodyToMono(String.class);
                    });

            response.setContentMono(contentMono);
            response.setContext(task.getContext());

        } catch (URISyntaxException e) {

        } finally {
            // TODO 打日志
        }
        return response;

    }

    /**
     * 请求 chrome 访问网页.
     */
    public void js() {

    }

    /**
     * 返回任务的 HTTP 请求方法
     * @param task
     * @return
     */
    private HttpMethod httpMethodResolver(final Task task) {
        HttpMethod httpMethod = HttpMethod.resolve(task.getMethod().toUpperCase());
        return httpMethod;
    }

    /**
     * 返回任务的 HTTP header
     * @param task
     * @return
     */
    private HttpHeaders httpHeadersResolver(final Task task) {
        if (task != null && MapUtils.isNotEmpty(task.getHeaders())) {
            HttpHeaders httpHeaders = new HttpHeaders();

            task.getHeaders().entrySet().stream().forEach(e -> {
                // 替换默认Header中的值
                httpHeaders.add(e.getKey(), e.getValue());
            });
            return httpHeaders;
        } else {
            return null;
        }
    }

    /**
     * 返回任务的 HTTP cookies
     * @param task
     * @return
     */
    private MultiValueMap<String, String> cookiesResolver(final Task task) {
        if (task != null && MapUtils.isNotEmpty(task.getCookies())) {
            MultiValueMap<String, String> cookies = new LinkedMultiValueMap<>();

            task.getHeaders().entrySet().stream().forEach(e -> {
                // 替换默认Cookeis中的值
                cookies.add(e.getKey(), e.getValue());
            });
            return cookies;
        } else {
            return null;
        }
    }

}



